#include "stdafx.h"
#include "ChunkFile.h"


ChunkFile::ChunkFile(const TCHAR *filename, bool _read)
{
  if (file.open(filename,_read ? FILE_READ : FILE_WRITE))
  {
    didFail=false;
  }
  else
  {
    didFail=true;
    return;
  }
#ifdef DEMO_VERSION
  if (!_read)
  {
    MessageBox(theApp->getHWND(),TEXT("DEMO VERSION: File Write Disabled"),TEXT("DEMO"),0);
    didFail=true;
    return;
  }
#endif

  int fSize = file.fileSize();
  eof=fSize;
  numLevels=0;
  read=_read;
  pos=0;
  didFail=false;
}

ChunkFile::~ChunkFile()
{
  file.close();
}


int ChunkFile::readInt()
{
  if (pos<eof)
  {
    /*
    int temp = *(int *)(data+pos);
    pos+=4;
    */
    pos+=4;
    return file.readInt();
  }
  else
  {
    return 0;
  }
}


void ChunkFile::writeInt(int i)
{
  /*
  *(int *)(data+pos) = i;
  pos+=4;
  */
  file.writeInt(i);
  pos+=4;
}

//let's get into the business
bool ChunkFile::descend(int32 id)
{
  id=flipID(id);
  if (read)
  {
    bool found = false;
    int startPos = pos;
    ChunkInfo temp = stack[numLevels];

    //save information to restore after the next Ascend
    stack[numLevels].parentStartLocation = pos;
    stack[numLevels].parentEOF = eof;


    int firstID = 0;
    //let's search through children..
    while(pos<eof)
    {
      stack[numLevels].ID = readInt();
      if (firstID == 0) firstID=stack[numLevels].ID|1;
      stack[numLevels].length = readInt();
      stack[numLevels].startLocation = pos;

      if (stack[numLevels].ID == id)
      {
        found = true;
        break;
      }
      else
      {
        seek(pos + stack[numLevels].length); //try next block
      }
    } 

    //if we found nothing, return false so the caller can skip this
    if (!found)
    {
      /*
      pos = startPos;
      char temp1[5]; TCHAR temp2[5];
      temp1[4]=0; temp2[4]=0;
      *(int *)temp1 =id;
      TCHAR tempx[256];

      for (int i=0; i<4; i++) 
        temp2[i]=temp1[i];
      
      _stprintf(tempx,TEXT("Couldn't find chunk \"%s\" in file"),temp2);

      MessageBox(theApp->getHWND(),tempx,0,0);
      */
      stack[numLevels]=temp;
      seek(stack[numLevels].parentStartLocation);
      return false;
    }

    //descend into it
    //pos was set inside the loop above
    eof = stack[numLevels].startLocation + stack[numLevels].length;
    numLevels++;
    return true;
  }
  else
  {
#ifndef DEMO_VERSION  //if this is missing.. heheh
    //write a chunk id, and prepare for filling in length later
    writeInt(id);
    writeInt(0); //will be filled in by Ascend
    stack[numLevels].startLocation=pos;
    numLevels++;
    return false;
#endif
    return true;
  }
}

void ChunkFile::seek(int _pos)
{
  file.seekBeg(_pos);
  pos=_pos;
}

//let's ascend out
void ChunkFile::ascend()
{
  if (read)
  {
    //ascend, and restore information
    numLevels--;
    seek(stack[numLevels].parentStartLocation);
    eof = stack[numLevels].parentEOF;
  }
  else 
  {
    numLevels--;
    //now fill in the written length automatically
    int posNow = pos;
    seek(stack[numLevels].startLocation - 4);
    writeInt(posNow-stack[numLevels].startLocation);
    seek(posNow);
  }
}

//read a block
void ChunkFile::readData(void *what, int count)
{
  /*
  memcpy(what,data+pos,count);
  pos += count;
  */
  file.read(what,count);
  pos+=count;
  char temp[4];
  count &= 3;
  if (count)
  {
    count=4-count;
    file.read(temp,count);
    pos+=count;
  }
}

//write a block
void ChunkFile::writeData(void *what, int count)
{
  /*
  memcpy(data+pos,what,count);
  pos += count;
  */
  file.write(what,count);
  pos+=count;
  char temp[5]={0,0,0,0,0};
  count &= 3; 
  if (count)
  {
    count=4-count;
    file.write(temp,count);
    pos+=count;
  }
}

void ChunkFile::writeString(String str)
{
  wchar_t *text;
  int len=str.length();
#ifdef UNICODE
  text = str.getPointer();
#else
  text=new wchar_t[len+1];
  str.toUnicode(text);
#endif
  writeInt(len);
  writeData((char *)text,len*sizeof(wchar_t));
#ifndef UNICODE
  delete [] text;
#endif
}


String ChunkFile::readString()
{
  int len=readInt();
  wchar_t *text = new wchar_t[len+1];
  readData((char *)text,len*sizeof(wchar_t));
  text[len]=0;
#ifdef UNICODE
  String s(text);
  delete [] text;
  return s;
#else
  String temp;
  temp.fromUnicode(text);
  delete [] text;
  return temp;
#endif
}